home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
kcl
/
kcl.lha
/
uts
/
hasegawa
/
ild.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-05-08
|
8KB
|
350 lines
/*
ild: incremental linker/loader on System V
(C) Masami Hagiya, 1986
UTS version (C) Akiumi Hasegawa, 1987
Usage:
% ild loading_object start_address \
loaded_object output_file
The start address is in decimal.
How to Create:
To compile this file (ild.c) and make ild, do the following.
% cc -o ild ild.c -lld
Problem:
This program only supports the simplest linear search for symbols.
This program is modified for UTS system.
*/
#include <stdio.h>
#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
#include <reloc.h>
#include <syms.h>
#include <storclass.h>
#include <ldfcn.h>
struct filehdr my_header;
struct syment *my_symbol_table;
char *my_string_table;
struct filehdr header;
struct aouthdr opt_header;
struct scnhdr section[9];
char *text;
struct syment *symbol_table;
char *string_table;
char *start_address;
struct reloc relocation_info;
main(argc, argv)
int argc;
char *argv[];
{
if (argc < 5) {
fprintf(stderr, "Arg count.\n");
exit(1);
}
#ifdef DEBUG
printf("ild %s %s %s %s\n", argv[1], argv[2], argv[3], argv[4]);
fflush(stdout);
#endif
get_myself(argv[1]);
start_address = (char *)atoi(argv[2]);
#ifdef DEBUG
printf("start address= %x\n",(int)start_address);fflush(stdout);
#endif
fasload(argv[3], argv[4]);
exit(0);
}
get_myself(filename)
char *filename;
{
int i;
LDFILE *ldptr;
extern char *malloc();
ldptr = ldopen(filename, NULL);
if (ldptr == NULL) {
fprintf(stderr, "Can't open %s\n", filename);
exit(1);
}
ldfhread(ldptr, &my_header);
ldtbseek(ldptr);
my_symbol_table
= (struct syment *)malloc(sizeof(struct syment) * my_header.f_nsyms);
/*
sizeof(struct syment) and SYMESZ are not always the same.
*/
if(my_symbol_table == NULL){
fprintf(stderr,"Can't allocate memory for my_symbol_table\n");
exit(1);
}
for (i = 0; i < my_header.f_nsyms; i++)
FREAD(&my_symbol_table[i], SYMESZ, 1, ldptr);
/*
If the string table is not empty,
its length is stored after the symbol table,
This is described in the manual.
(see UTS Support Tools Guide V10L20)
*/
if (FREAD(&i, 4, 1, ldptr) > 0) {
my_string_table = malloc(i);
FSEEK(ldptr, -4, 1);
FREAD(my_string_table, 1, i, ldptr);
}
ldclose(ldptr);
}
fasload(filename, outputfilename)
char *filename, *outputfilename;
{
register struct syment *sym, *end;
int i, n;
LDFILE *ldptr;
FILE *fp;
extern char *malloc();
ldptr = ldopen(filename, "r");
if (ldptr == NULL) {
fprintf(stderr, "Can't open %s\n", filename);
exit(1);
}
ldfhread(ldptr, &header);
FREAD(&opt_header,sizeof(struct aouthdr),1,ldptr);
if (header.f_nscns < 3 || header.f_nscns > 8) {
fprintf(stderr, "Illegal number of sections.\n");
exit(1);
}
for (i = 1; i <= header.f_nscns; i++)
ldshread(ldptr, i, §ion[i]);
if (strcmp(section[1].s_name, ".text") != 0) {
fprintf(stderr, ".text not found.\n");
exit(1);
}
if (strcmp(section[2].s_name, ".data") != 0) {
fprintf(stderr, ".data not found.\n");
exit(1);
}
/*
The bss segment need not exist.
*/
/*
if (strcmp(section[3].s_name, ".bss") != 0) {
fprintf(stderr, ".bss not found.\n");
exit(1);
}
*/
if (section[1].s_size > 0 &&
section[1].s_scnptr !=
sizeof(struct filehdr) + sizeof(struct aouthdr) +
header.f_nscns*sizeof(struct scnhdr)) {
fprintf(stderr, "Contradictory text start.\n");
exit(1);
}
if (section[1].s_size > 0 && section[2].s_size > 0 &&
section[1].s_scnptr + section[1].s_size !=
section[2].s_scnptr) {
fprintf(stderr, "Contradictory data start.\n");
exit(1);
}
text = malloc(section[1].s_size + section[2].s_size);
FSEEK(ldptr, section[1].s_scnptr, 0);
FREAD(text, 1, section[1].s_size + section[2].s_size, ldptr);
ldtbseek(ldptr);
symbol_table
= (struct syment *)malloc(sizeof(struct syment) * header.f_nsyms);
/*
sizeof(struct syment) and SYMESZ are not always the same.
*/
for (i = 0; i < header.f_nsyms; i++)
FREAD(&symbol_table[i], SYMESZ, 1, ldptr);
/*
If the string table is not empty,
its length is stored after the symbol table,
This is described in the manual.
(see UTS Support Tools Guide V10L20)
*/
if (FREAD(&i, 4, 1, ldptr) > 0) {
string_table = malloc(i);
FSEEK(ldptr, -4, 1);
FREAD(string_table, 1, i, ldptr);
}
end = symbol_table + header.f_nsyms;
for (sym = symbol_table; sym < end; sym++) {
switch (sym->n_scnum) {
/* in UTS, relocatable address is the offset in the
section, in which it defined.
Thus "sym->n_value" for each section should be
the the top address of the section.
in case of ".data" section, s_vaddr is equal to
s_size. However, ".bss" section, s_vaddr <>
textsize+datasize. I cannot understand why. But
this code works well.
*/
case 1:
/* .text */
sym->n_value = (int)start_address; break;
case 2:
/* .data */
sym->n_value = (int)start_address + section[1].s_size;
break;
case 3:
/* .bss */
sym->n_value = (int)start_address + section[1].s_size
+ section[2].s_size;
break;
case N_UNDEF:
search_symbol(sym);
break;
default:
/*
Does nothing. Is it OK?
*/
break;
}
sym += sym->n_numaux;
}
if(ldrseek(ldptr, 1) ==FAILURE){
fprintf(stderr,"Can't locate relocation table\n");
exit(1);
}
for (i=0; i< section[1].s_nreloc; i++){
FREAD(&relocation_info,10,1,ldptr);
relocate();
}
ldrseek(ldptr, 2);
for (i = 0; i < section[2].s_nreloc; i++) {
FREAD(&relocation_info, 10, 1, ldptr);
relocate();
}
fp = fopen(outputfilename, "w");
if (fp == NULL) {
fprintf(stderr, "Can't creat %s.\n", outputfilename);
exit(1);
}
fwrite(&header, sizeof(struct filehdr), 1, fp);
fwrite(&opt_header,sizeof(struct aouthdr),1,fp);
for (i = 1; i<= header.f_nscns; i++)
fwrite(§ion[i], sizeof(struct scnhdr), 1, fp);
fwrite(text, 1, section[1].s_size + section[2].s_size, fp);
fclose(fp);
ldclose(ldptr);
}
search_symbol(sym)
register struct syment *sym;
{
register struct syment *p, *end;
end = my_symbol_table + my_header.f_nsyms;
for (p = my_symbol_table; p < end; p++) {
/*
Is the following check enough?
*/
if (1 <= p->n_scnum && p->n_scnum <= 3 &&
p->n_sclass == C_EXT &&
(sym->n_zeroes == 0
? (p->n_zeroes == 0 &&
strcmp(&my_string_table[p->n_offset],
&string_table[sym->n_offset]) == 0)
: (p->n_zeroes != 0 &&
strncmp(p->n_name, sym->n_name, SYMNMLEN) == 0)))
goto FOUND;
p += p->n_numaux;
}
sym->n_name[SYMNMLEN] = '\0';
fprintf(stderr, "%s: undefined symbol.\n",
(sym->n_zeroes ? sym->n_name : &string_table[sym->n_offset]));
exit(1);
FOUND:
sym->n_value = p->n_value;
}
relocate()
{
char *where, *p;
int value;
where = text + relocation_info.r_vaddr;
if (relocation_info.r_type == R_ABS)
return;
/*
The following code depends on CPU.
in case of UTS, R_RELLONG is assumed.
*/
if (relocation_info.r_type != R_RELLONG) {
fprintf(stderr, "%d: unsupported relocation type.",
relocation_info.r_type);
exit(1);
}
/*
Assuming R_RELLONG.
*/
p = (char *)(&value);
p[0] = where[0];
p[1] = where[1];
p[2] = where[2];
p[3] = where[3];
#ifdef DEBUG
printf("%s\n",
(symbol_table[relocation_info.r_symndx].n_zeroes ?
symbol_table[relocation_info.r_symndx].n_name :
&string_table
[symbol_table[relocation_info.r_symndx].n_offset]));
printf("value = %x\n",value);fflush(stdout);
#endif
value += symbol_table[relocation_info.r_symndx].n_value;
#ifdef DEBUG
printf("value = %x\n",value);fflush(stdout);
#endif
where[0] = p[0];
where[1] = p[1];
where[2] = p[2];
where[3] = p[3];
}